Skip to content

feat(web-ui): add template editor to claude config panel#167

Merged
ymkiux merged 8 commits into
mainfrom
feat/claude-template-editor
May 19, 2026
Merged

feat(web-ui): add template editor to claude config panel#167
ymkiux merged 8 commits into
mainfrom
feat/claude-template-editor

Conversation

@ymkiux
Copy link
Copy Markdown
Collaborator

@ymkiux ymkiux commented May 19, 2026

Summary

  • Add template editor button to Claude config panel Model section, aligned with Codex position
  • Reuse existing configTemplate modal, context-aware apply via configTemplateContext flag
  • Claude reads/writes ~/.claude/settings.json via get-claude-settings-raw / apply-claude-settings-raw APIs

Tests

  • Click template editor button in Claude tab opens modal with settings.json content
  • Edit and apply saves to ~/.claude/settings.json
  • Codex template editor still works unchanged

Summary by CodeRabbit

  • New Features

    • Template editor for Claude configuration with a dedicated button; applying templates now supports multiple config types.
    • New Codex and Claude "bridge-pool" modals to view and enable/disable upstream providers, plus card-level buttons to open them.
    • Inline bridge-pool summaries on Codex and Claude provider cards showing enabled vs total candidates.
  • Style

    • New styles for bridge-pool summaries, modal layout, and list scrolling.
  • Behavior

    • Improved automatic detection for Claude-local configurations.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

Adds a Claude config-template editor and context-aware template application; moves Codex/Claude bridge-pool controls into modal dialogs, adds card-level bridge-pool summaries and trigger buttons, and introduces supporting CSS.

Changes

Template editor and bridge-pool UI

Layer / File(s) Summary
State and template editor entry points
web-ui/app.js, web-ui/modules/app.methods.claude-config.mjs, web-ui/modules/app.methods.codex-config.mjs, web-ui/partials/index/panel-config-claude.html, tests/unit/web-ui-behavior-parity.test.mjs
Adds showCodexBridgePoolModal and showClaudeBridgePoolModal booleans and configTemplateContext (default 'codex'). Adds openClaudeConfigTemplateEditor() method and ensures Codex editor sets context to 'codex'. Adds Claude panel button to open the Claude template editor. Parity tests updated to accept the new data/method keys.
Context-aware template application & Claude local bridge
web-ui/modules/app.methods.codex-config.mjs, web-ui/modules/app.methods.claude-config.mjs, web-ui/logic.claude.mjs
applyConfigTemplate() now selects API by configTemplateContext: uses apply-claude-settings-raw when 'claude', otherwise apply-config-template. Adds applyClaudeLocalBridge() to enable the claude-local bridge and openClaudeConfigTemplateEditor() to load Claude raw settings into the template editor. matchClaudeConfigFromSettings now returns 'claude-local' for /bridge/claude-local/ URLs.
Bridge-pool modals, card summaries, and styles
web-ui/partials/index/modals-basic.html, web-ui/partials/index/panel-config-claude.html, web-ui/partials/index/panel-config-codex.html, web-ui/styles/bridge-pool.css
Adds Codex and Claude bridge-pool modals with provider lists and toggle checkboxes; replaces inline per-provider bridge-pool panels with compact card summaries and card action buttons that open the modals; introduces CSS for bridge-pool summaries, modal layout, and scrolling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • SakuraByteCore/codexmate#91: Overlaps with changes to the config-template apply workflow in web-ui/modules/app.methods.codex-config.mjs.

Suggested reviewers

  • awsl233777

Poem

🐰 I hopped through templates, tidy and spry,
Moved bridge pools to modals, now neatify.
Claude and Codex each find their place,
Context set, the modal shows its face.
A little rabbit cheers with a happy sigh!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(web-ui): add template editor to claude config panel' directly and clearly summarizes the main change: adding a template editor feature to the Claude configuration panel UI. It is concise, specific, and accurately reflects the primary objective of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/claude-template-editor

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web-ui/modules/app.methods.codex-config.mjs`:
- Around line 811-820: The preview gating logic for config applies is using the
shared "preview-config-template-diff" path even when configTemplateContext ===
'claude', causing Claude-mode applies to be blocked/misrepresented; update
applyConfigTemplate() (or the code path that checks
preview-config-template-diff) to skip or bypass the shared diff-preview gate
when this.configTemplateContext === 'claude' (or alternatively propagate the
'claude' context so the preview check uses a Claude-aware gate), ensuring the
Claude branch that calls api('apply-claude-settings-raw', ...) is not forced
through the generic preview gate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3e5201af-fa5c-47fd-a115-3c2be8c90e57

📥 Commits

Reviewing files that changed from the base of the PR and between 36cb09f and 7f61020.

📒 Files selected for processing (4)
  • web-ui/app.js
  • web-ui/modules/app.methods.claude-config.mjs
  • web-ui/modules/app.methods.codex-config.mjs
  • web-ui/partials/index/panel-config-claude.html
📜 Review details
🔇 Additional comments (4)
web-ui/app.js (1)

101-101: LGTM!

web-ui/modules/app.methods.claude-config.mjs (1)

269-282: LGTM!

web-ui/partials/index/panel-config-claude.html (1)

85-85: LGTM!

web-ui/modules/app.methods.codex-config.mjs (1)

561-562: LGTM!

Comment on lines +811 to +820
let res;
if (this.configTemplateContext === 'claude') {
res = await api('apply-claude-settings-raw', {
content: this.configTemplateContent
});
} else {
res = await api('apply-config-template', {
template: this.configTemplateContent
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Claude apply path is context-aware, but confirmation preview gating is not.

At Line 812 you route apply correctly, but applyConfigTemplate() still enforces the shared diff-preview gate (preview-config-template-diff) with no Claude context. In Claude mode this can block or mislead apply decisions based on the wrong target.

Suggested frontend-safe fix (bypass codex diff gate for Claude context)
 async applyConfigTemplate() {
     if (this.configTemplateApplying) {
         return;
     }
     if (!this.configTemplateContent || !this.configTemplateContent.trim()) {
         this.showMessage('模板不能为空', 'error');
         return;
     }

+    const isClaudeTemplate = this.configTemplateContext === 'claude';
     // Default to two-step confirmation when the setting is unset.
     // (The normalize helper lives in session-actions; keep a safe fallback here.)
-    const shouldUseTwoStepConfirm = normalizeConfigTemplateDiffConfirmEnabled(this.configTemplateDiffConfirmEnabled);
+    const shouldUseTwoStepConfirm = !isClaudeTemplate
+        && normalizeConfigTemplateDiffConfirmEnabled(this.configTemplateDiffConfirmEnabled);

     const performApply = async () => {
         this.configTemplateApplying = true;
         try {
             let res;
             if (this.configTemplateContext === 'claude') {
                 res = await api('apply-claude-settings-raw', {
                     content: this.configTemplateContent
                 });
             } else {
                 res = await api('apply-config-template', {
                     template: this.configTemplateContent
                 });
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-ui/modules/app.methods.codex-config.mjs` around lines 811 - 820, The
preview gating logic for config applies is using the shared
"preview-config-template-diff" path even when configTemplateContext ===
'claude', causing Claude-mode applies to be blocked/misrepresented; update
applyConfigTemplate() (or the code path that checks
preview-config-template-diff) to skip or bypass the shared diff-preview gate
when this.configTemplateContext === 'claude' (or alternatively propagate the
'claude' context so the preview check uses a Claude-aware gate), ensuring the
Claude branch that calls api('apply-claude-settings-raw', ...) is not forced
through the generic preview gate.

ymkiux added 7 commits May 19, 2026 21:43
- Show pool status summary above local provider title
- Add modal dialog for pool management (Codex & Claude)
- Add trigger button in local card actions
- Remove standalone bridge-pool-panel
- Add applyClaudeLocalBridge() method to enable local bridge
- Local card click now calls API to write config to file
- Refresh will persist local selection
…ider

- Match claude-local when URL contains /bridge/claude-local/
- Prevents creating '导入-127.0.0.1:xxxx' provider on refresh
- Remove local card from Claude config panel
- Remove Claude bridge pool modal
- Keep Codex local provider functional
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web-ui/logic.claude.mjs`:
- Around line 114-117: The local-bridge URL check inside web-ui/logic.claude.mjs
is too strict — the current conditional that inspects normalizedSettings.baseUrl
only matches '/bridge/claude-local/' and misses URLs without a trailing slash;
update the detection logic (the conditional referencing
normalizedSettings.baseUrl in this module) to treat '/bridge/claude-local' and
'/bridge/claude-local/' (and any URL where '/bridge/claude-local' is a path
segment) as matches — e.g., replace the exact include check with a test that
accepts either a trailing slash or end-of-string (or use startsWith or a regex
like '/bridge/claude-local(\/|$)') so the function returns 'claude-local' for
both forms.

In `@web-ui/modules/app.methods.claude-config.mjs`:
- Around line 269-288: The method applyClaudeLocalBridge currently sets
this.currentClaudeConfig = 'claude-local' and writes localStorage before the API
call, causing stale UI state if validation or api('claude-local-bridge-toggle',
{ enable: true }) fails; change the flow in applyClaudeLocalBridge so you first
validate candidates via claudeLocalBridgeCandidateProviders(), then call the
API, and only on successful response set this.currentClaudeConfig =
'claude-local', persist to localStorage, and call
this.refreshClaudeModelContext(); if the API returns an error or throws, do not
modify currentClaudeConfig or localStorage (or revert them if already changed),
and continue to show the existing error messages via this.showMessage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 790b6463-247f-487e-8c8a-77011e759060

📥 Commits

Reviewing files that changed from the base of the PR and between e0da110 and 9789805.

📒 Files selected for processing (5)
  • tests/unit/web-ui-behavior-parity.test.mjs
  • web-ui/logic.claude.mjs
  • web-ui/modules/app.methods.claude-config.mjs
  • web-ui/partials/index/modals-basic.html
  • web-ui/partials/index/panel-config-claude.html
🚧 Files skipped from review as they are similar to previous changes (1)
  • web-ui/partials/index/panel-config-claude.html
📜 Review details
🔇 Additional comments (3)
web-ui/modules/app.methods.claude-config.mjs (1)

291-304: LGTM!

tests/unit/web-ui-behavior-parity.test.mjs (1)

414-429: LGTM!

Also applies to: 577-578

web-ui/partials/index/modals-basic.html (1)

175-198: LGTM!

Comment thread web-ui/logic.claude.mjs
Comment on lines +114 to +117
// 检测本地桥接 URL
if (typeof normalizedSettings.baseUrl === 'string' && normalizedSettings.baseUrl.includes('/bridge/claude-local/')) {
return 'claude-local';
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Local-bridge URL detection is too strict and misses valid forms.

The current check only matches /bridge/claude-local/. URLs without trailing slash (e.g., /bridge/claude-local) won’t match.

Proposed fix
-    if (typeof normalizedSettings.baseUrl === 'string' && normalizedSettings.baseUrl.includes('/bridge/claude-local/')) {
+    const normalizedBaseUrl = normalizeClaudeComparableUrl(normalizedSettings.baseUrl).toLowerCase();
+    if (normalizedBaseUrl.includes('/bridge/claude-local')) {
         return 'claude-local';
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-ui/logic.claude.mjs` around lines 114 - 117, The local-bridge URL check
inside web-ui/logic.claude.mjs is too strict — the current conditional that
inspects normalizedSettings.baseUrl only matches '/bridge/claude-local/' and
misses URLs without a trailing slash; update the detection logic (the
conditional referencing normalizedSettings.baseUrl in this module) to treat
'/bridge/claude-local' and '/bridge/claude-local/' (and any URL where
'/bridge/claude-local' is a path segment) as matches — e.g., replace the exact
include check with a test that accepts either a trailing slash or end-of-string
(or use startsWith or a regex like '/bridge/claude-local(\/|$)') so the function
returns 'claude-local' for both forms.

Comment on lines +269 to +288
async applyClaudeLocalBridge() {
this.currentClaudeConfig = 'claude-local';
try { localStorage.setItem('currentClaudeConfig', 'claude-local'); } catch (_) {}
this.refreshClaudeModelContext();

const candidates = this.claudeLocalBridgeCandidateProviders();
if (candidates.length === 0) {
return this.showMessage('请先添加并配置至少一个 Claude 提供商', 'error');
}

try {
const res = await api('claude-local-bridge-toggle', { enable: true });
if (res.error) {
this.showMessage(res.error || '启用本地负载均衡失败', 'error');
return;
}
this.showMessage('Claude 本地负载均衡已启用', 'success');
} catch (e) {
this.showMessage('启用本地负载均衡失败', 'error');
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Switching to claude-local before enable succeeds leaves stale UI state.

If validation or claude-local-bridge-toggle fails, the app still persists currentClaudeConfig='claude-local'. Keep current selection unchanged until enable succeeds.

Proposed fix
         async applyClaudeLocalBridge() {
-            this.currentClaudeConfig = 'claude-local';
-            try { localStorage.setItem('currentClaudeConfig', 'claude-local'); } catch (_) {}
-            this.refreshClaudeModelContext();
-
             const candidates = this.claudeLocalBridgeCandidateProviders();
             if (candidates.length === 0) {
                 return this.showMessage('请先添加并配置至少一个 Claude 提供商', 'error');
             }
 
             try {
                 const res = await api('claude-local-bridge-toggle', { enable: true });
                 if (res.error) {
                     this.showMessage(res.error || '启用本地负载均衡失败', 'error');
                     return;
                 }
+                this.currentClaudeConfig = 'claude-local';
+                try { localStorage.setItem('currentClaudeConfig', 'claude-local'); } catch (_) {}
+                this.refreshClaudeModelContext();
                 this.showMessage('Claude 本地负载均衡已启用', 'success');
             } catch (e) {
                 this.showMessage('启用本地负载均衡失败', 'error');
             }
         },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async applyClaudeLocalBridge() {
this.currentClaudeConfig = 'claude-local';
try { localStorage.setItem('currentClaudeConfig', 'claude-local'); } catch (_) {}
this.refreshClaudeModelContext();
const candidates = this.claudeLocalBridgeCandidateProviders();
if (candidates.length === 0) {
return this.showMessage('请先添加并配置至少一个 Claude 提供商', 'error');
}
try {
const res = await api('claude-local-bridge-toggle', { enable: true });
if (res.error) {
this.showMessage(res.error || '启用本地负载均衡失败', 'error');
return;
}
this.showMessage('Claude 本地负载均衡已启用', 'success');
} catch (e) {
this.showMessage('启用本地负载均衡失败', 'error');
}
async applyClaudeLocalBridge() {
const candidates = this.claudeLocalBridgeCandidateProviders();
if (candidates.length === 0) {
return this.showMessage('请先添加并配置至少一个 Claude 提供商', 'error');
}
try {
const res = await api('claude-local-bridge-toggle', { enable: true });
if (res.error) {
this.showMessage(res.error || '启用本地负载均衡失败', 'error');
return;
}
this.currentClaudeConfig = 'claude-local';
try { localStorage.setItem('currentClaudeConfig', 'claude-local'); } catch (_) {}
this.refreshClaudeModelContext();
this.showMessage('Claude 本地负载均衡已启用', 'success');
} catch (e) {
this.showMessage('启用本地负载均衡失败', 'error');
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-ui/modules/app.methods.claude-config.mjs` around lines 269 - 288, The
method applyClaudeLocalBridge currently sets this.currentClaudeConfig =
'claude-local' and writes localStorage before the API call, causing stale UI
state if validation or api('claude-local-bridge-toggle', { enable: true })
fails; change the flow in applyClaudeLocalBridge so you first validate
candidates via claudeLocalBridgeCandidateProviders(), then call the API, and
only on successful response set this.currentClaudeConfig = 'claude-local',
persist to localStorage, and call this.refreshClaudeModelContext(); if the API
returns an error or throws, do not modify currentClaudeConfig or localStorage
(or revert them if already changed), and continue to show the existing error
messages via this.showMessage.

@ymkiux ymkiux merged commit 7566d89 into main May 19, 2026
7 checks passed
@ymkiux ymkiux deleted the feat/claude-template-editor branch May 19, 2026 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant